import os,io,requests,math,traceback,pytesseract,re,time
from PIL import Image
from bs4 import BeautifulSoup
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait as wait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains as action
from selenium.common.exceptions import TimeoutException
from support.dbms.helper import SQLHelper
from support.assets.star import StarConfidence
from support.utils.dir import Dir


class MorningStar:
    LOGIN_URL = 'https://www.morningstar.cn/membership/signin.aspx'
    FUND_SELECTOR_URL = "https://www.morningstar.cn/fundselect/default.aspx"
    FUND_DETAIL_URL = "https://www.morningstar.cn/quicktake/"

    def __init__(self, driver):
        self.driver = driver
        self.helper = SQLHelper(os.getenv("MS_DB_NAME"), os.getenv("MS_DB_HOST"), os.getenv("MS_DB_USERNAME"), os.getenv("MS_DB_PASSWORD"))
        self.sc = StarConfidence()

    def close(self):
        self.helper.close()
        self.sc.clean()

    def __getVerificationCode(self):
        code = None
        try:
            codepath = Dir.autoCreateDir(os.getcwd(), 'tmp')
            elecode = self.driver.find_element(By.ID, "checkcodeImg")
            elecode.screenshot(os.path.join(codepath, 'code.png'))
            image = Image.open(os.path.join(codepath, 'code.png'))
            custom_oem_psm_config = '--oem 0 --psm 13 --tessdata-dir /var/wss/tessdata/ digits'
            identify_code = pytesseract.image_to_string(
                image, config=custom_oem_psm_config)
            code = "".join(identify_code.split()).strip('‘')
        except:
            traceback.print_exc()
        return code

    def __loginSuccess(self):
        state = False
        try:
            wait(self.driver,20).until(EC.visibility_of_element_located((By.ID, 'message-container')))
            message_box = self.driver.find_element_by_id(
                'message-container')
            print(message_box.find_element_by_xpath('.//div[@class="message"]').get_attribute('textContent'))
            close_btn = message_box.find_element(
                By.CLASS_NAME, "modal-close")
            close_btn.click()
        except TimeoutException:
            state = True
        finally:
            return state

    def __textTobePresentInElement(self, locator, text, next_page_locator):
        def _predicate(driver):
            try:
                element_text = driver.find_element_by_xpath(locator).text
                if int(element_text) != int(text):
                    js_content = "javascript:__doPostBack('ctl00$cphMain$AspNetPager1','{}')".format(
                        text)
                    execute_return = driver.execute_script(js_content)
                    print('execute_return', execute_return)
                    time.sleep(5)
    
                return text == element_text
            except:
                return False
    
        return _predicate

    def __refluseFundBaseInfo(self):
        mscodelist = []
        self.driver.get(MorningStar.FUND_SELECTOR_URL)
        try:
            page_num = 1
            page_count = 25
            page_num_total = math.ceil(int(self.driver.find_element_by_xpath(
                '//span[contains(@id, "TotalResultLabel")]').text) / page_count)
            while page_num <= page_num_total:
                remainder = page_num_total % 10
                num = (remainder +
                       2) if page_num > (page_num_total - remainder) else 12
                xpath_str = '/html/body/form/div[8]/div/div[4]/div[3]/div[3]/div[1]/a[%s]' % (
                    num)
                wait(self.driver, timeout=600).until(self.__textTobePresentInElement(
                    "/html/body/form/div[8]/div/div[4]/div[3]/div[3]/div[1]/span[@style='margin-right:5px;font-weight:Bold;color:red;']", str(page_num), xpath_str))
                data = self.driver.page_source
                bs = BeautifulSoup(data, 'lxml')
                class_list = ['gridItem', 'gridAlternateItem']
                for i in range(len(class_list)):
                    for tr in bs.find_all('tr', {'class': class_list[i]}):
                        tds_text = tr.find_all('td', {'class': "msDataText"})
                        tds_nume = tr.find_all('td', {'class': "msDataNumeric"})
                        code_a_element = tds_text[0].find_all('a')[0]
                        fundcode = str(code_a_element.string)
                        mscode = re.findall(
                            r'(?<=/quicktake/)(\w+)$', code_a_element.get('href')).pop(0)
                        name = str(tds_text[1].find_all('a')[0].string)
                        fundtype = str(tds_text[2].string)
                        threerating = self.sc.getStarNum(tds_text[3].find_all('img')[0]['src'])
                        fiverating = self.sc.getStarNum(tds_text[4].find_all('img')[0]['src'])
                        rateofreturn = float(tds_nume[3].string) if tds_nume[3].string != '-' else 0
                        self.helper.updateFundBaseInfo(fundcode, mscode, name, fundtype, threerating, fiverating, rateofreturn)
                        mscodelist.append(mscode)
                print('page {} parse completed!'.format(page_num))
                next_page = self.driver.find_element_by_xpath(
                    xpath_str)
                next_page.click()
                time.sleep(3)
                page_num += 1
        except:
            traceback.print_exc()
        return mscodelist

    def __refluseProfileInfo(self, mscode):
        self.driver.get("{}{}".format(MorningStar.FUND_DETAIL_URL, mscode))
        try:
            wait(self.driver,20).until(EC.visibility_of_element_located((By.ID, 'qt_10k')))
            sbdesc = self.driver.find_element_by_xpath('//span[@class="sbdesc"]').get_attribute('textContent')
            time = self.driver.find_element_by_xpath('//span[@class="inception"]').get_attribute('textContent')
            asset = self.driver.find_element_by_xpath('//span[@class="asset"]').get_attribute('textContent')
            minunit = self.driver.find_element_by_xpath('//span[@class="min"]').get_attribute('textContent')
            subscribe = self.driver.find_element_by_xpath('//span[@class="subscribe"]').get_attribute('textContent')
            redeem = self.driver.find_element_by_xpath('//span[@class="redeem"]').get_attribute('textContent')
            front = self.driver.find_element_by_xpath('//span[@class="front" and contains(text(), "%")]').get_attribute('textContent')
            profile = self.driver.find_element_by_xpath('//span[contains(@class, "profile")]').get_attribute('textContent')
            self.helper.updateFundFileInfo(mscode, time, minunit, float(asset), sbdesc, front, '-', subscribe, redeem, profile)
        except:
            print("fluse {} failed!".format(mscode))

    def __refluseRiskInfo(self, mscode):
        rr = self.driver.find_element_by_xpath('//ul[@id="qt_risk"]/li[9]').get_attribute('textContent')
        sd = self.driver.find_element_by_xpath('//ul[@id="qt_risk"]/li[16]').get_attribute('textContent')
        msindex = self.driver.find_element_by_xpath('//ul[@id="qt_risk"]/li[23]').get_attribute('textContent')
        sharperatio = self.driver.find_element_by_xpath('//ul[@id="qt_risk"]/li[30]').get_attribute('textContent')
        alpha = self.driver.find_element_by_xpath('//ul[@id="qt_riskstats"]/li[5]').get_attribute('textContent')
        beta = self.driver.find_element_by_xpath('//ul[@id="qt_riskstats"]/li[8]').get_attribute('textContent')
        rs = self.driver.find_element_by_xpath('//ul[@id="qt_riskstats"]/li[11]').get_attribute('textContent')
        if(rr == '-'):
            rr = '1029'
        if(alpha == "-"):
            alpha = "1029"
        if(beta == "-"):
            beta = "1029"
        if(rs == "-"):
            rs = "1029"
        if(sd == "-"):
            sd = "1029"
        if(msindex == "-"):
            msindex = "1029"
        if(sharperatio == "-"):
            sharperatio = "1029"
        self.helper.updateFundRiskInfo(mscode, float(alpha), float(beta), float(rs), float(rr), float(sd), float(msindex), float(sharperatio))

    def login(self, username, passwd, redirecturl):
        islogin = False
        url = MorningStar.LOGIN_URL if redirecturl is None else "{}?ReturnUrl=[]".format(MorningStar.LOGIN_URL, redirecturl)
        self.driver.get(url)
        wait(self.driver, 10).until(EC.visibility_of_element_located((By.ID, 'loginGo')))
        self.driver.find_element_by_id('emailTxt').send_keys(username)
        self.driver.find_element_by_id('pwdValue').send_keys(passwd)
        try:
            for i in range(10):
                verificationCode = self.__getVerificationCode()
                if(not verificationCode):
                    self.driver.get(url)
                    wait(self.driver,10).until(EC.visibility_of_element_located((By.ID, 'loginGo')))
                    self.driver.find_element_by_id('emailTxt').send_keys(username)
                    self.driver.find_element_by_id('pwdValue').send_keys(passwd)
                    continue
                elecode = self.driver.find_element_by_id('txtCheckCode')
                elecode.clear()
                elecode.send_keys(verificationCode)
                self.driver.find_element_by_id('loginGo').click()
                if(self.__loginSuccess()):
                    islogin = True
                    break
                else:
                    print('verification code:{} username:{} password:{} Login failed!'.format(verificationCode, username, passwd))
        except:
            traceback.print_exc()
        return islogin

    def refluseFundInfo(self, refluse, three, five):
        mscodelist = []
        if(refluse):
            mscodelist = self.__refluseFundBaseInfo()
        else:
            self.helper.getAllMSCode(mscodelist, three, five)
            for mscode in mscodelist:
                self.__refluseProfileInfo(mscode)
                self.__refluseRiskInfo(mscode)
        return len(mscodelist)
